package com.zeng.plugin;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.google.common.base.CaseFormat;
import com.zeng.plugin.entity.MenuView;
import com.zeng.plugin.entity.RowEntity;
import com.zeng.plugin.entity.TableEntity;
import com.zeng.plugin.entity.TableRelative;
import com.zeng.plugin.intefaceHandle.impl.*;
import com.zeng.plugin.util.*;
import freemarker.template.utility.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Mojo(name = "create-class", requiresProject = false)
public class CreateClassPlugin extends AbstractMojo {

    @Parameter(property = "sayhi.voModule")
    String voModule;
    @Parameter(property = "sayhi.serviceimplModule")
    String serviceimplModule;

    @Parameter(property = "sayhi.serviceModule")
    String serviceModule;

    @Parameter(property = "sayhi.controllerModule")
    String controllerModule;

    @Parameter(property = "basedir")
    String basedir;

    @Parameter(property = "project.build.directory")
    String directory;

    @Parameter(property = "project.groupId")
    String groupId;

    @Parameter(property = "project.artifactId")
    String artifactId;

    String javaPath = new File("").getAbsolutePath() + "\\src\\main\\java";

    @Parameter(property = "sayhi.prefix", defaultValue = "yl")
    String prefix;

    @Parameter(property = "sayhi.mapperModule")
    String mapperModule;

    @Parameter(property = "sayhi.pojoModule")
    String pojoModule;

//    File file = new File("C:\\Users\\51399\\Desktop\\template\\com.zeng.md-test\\data.z");
    File file = new File("./../../data.z");

    List<TableEntity> tableEntities;

    // vo文件需要添加的对象包
    Map<String, List<String>> voPackageExtendString = new HashMap<>();
    // vo文件需要添加的对象
    Map<String, List<String>> voPropertyExtendString = new HashMap<>();
    // service文件需要添加的对象包和方法
    Map<String, List<String>> servicePackageExtendString = new HashMap<>();
    Map<String, List<String>> serviceMethodExtendString = new HashMap<>();
    // serviceimpl 文件需要添加的对象包和方法
    Map<String, List<String>> serviceimplPackageExtendString = new HashMap<>();
    Map<String, List<String>> serviceimplMethodExtendString = new HashMap<>();
    Map<String, List<String>> serviceimplPropertyExtendString = new HashMap<>();
    // mapper 文件需要添加的对象包和方法
    Map<String, List<String>> mapperPackageExtendString = new HashMap<>();
    Map<String, List<String>> mapperMethodExtendString = new HashMap<>();
    // mapperxml 文件需要添加的对象包和方法
    Map<String, List<String>> mapperXmlExtendString = new HashMap<>();
    // warpper 文件需要添加的对象包和方法
    Map<String, List<String>> wrapperExtendString = new HashMap<>();
    // controller
    Map<String, List<String>> controllerPackageExtendString = new HashMap<>();
    Map<String, List<String>> controllerMethodExtendString = new HashMap<>();
    Map<String, List<String>> controllerPropertyExtendString = new HashMap<>();

    Map<String, String> resultMapMeta = null;
    /*
     * mapperPackage
     * entityPackage
     * servicePackage
     * serviceimplPackage
     * voPackage
     * controllerPackage
     * */
    @Parameter(property = "sayhi.packageMaps")
    Map<String, String> packageMaps;

    private String tableInfoXmlName = "\\tables.xml";

    private String tamplateDir;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        this.directory = new File("./").getAbsolutePath();
        this.tamplateDir = new File(directory + "\\template").getAbsolutePath();
        getLog().info(basedir);

        if (StringUtils.isEmpty(packageMaps.get("entityPackage"))) {
            throw new RuntimeException("entityPackage不能为空");
        }
        initWraperPackage(packageMaps);

        String mapperJavaPath = getJavaPath(directory, mapperModule, packageMaps.get("mapperPackage"));
        String voJavaPath = getJavaPath(directory, voModule, packageMaps.get("voPackage"));
        String servicePath = getJavaPath(directory, serviceModule, packageMaps.get("servicePackage"));
        String serviceimplPath = getJavaPath(directory, serviceimplModule, packageMaps.get("serviceimplPackage"));
        String controllerPath = getJavaPath(directory, controllerModule, packageMaps.get("controllerPackage"));
        String wrapperPath = getJavaPath(directory, voModule, packageMaps.get("wrapperPackage"));

        getLog().info("entityPackage --:" + packageMaps.get("entityPackage"));
        getLog().info("directory --:" + directory);
        getLog().info("prefix --:" + prefix);

        String pojoResourceDir = new File(".\\" + pojoModule + "\\src\\main\\resources").getAbsolutePath();
        getLog().info("pojoResourceDir --:" + pojoResourceDir);
        prefix = (String) ((Map<String, Object>) getDataz().get("pom")).get("tablePrefix");
        CreatePojo createPojo = new CreatePojo(pojoResourceDir, packageMaps.get("entityPackage"), prefix);
        try {
            FreeMarkUtil freeMarkUtil = new FreeMarkUtil(tamplateDir);
//            ParseXmlUtil parseXmlUtil = new ParseXmlUtil();
//            parseXmlUtil.parse(new File(tamplateDir + tableInfoXmlName).getAbsolutePath());
            tableEntities = this.getTableEntitys();
            // init 过程
            this.initTableNameWithPrefix(tableEntities, prefix);
            resultMapMeta = initResultMapMeta(tableEntities);
            handleRelative();

            Map<String, MenuView> menuView = (Map<String, MenuView>) getDataz().get("menuView");
            if (menuView != null) {
                MenuViewHandle menuViewHandle = new MenuViewHandle(menuView);
                menuViewHandle.handleController(controllerPackageExtendString, controllerMethodExtendString, controllerPropertyExtendString);
                menuViewHandle.handleService(servicePackageExtendString, serviceMethodExtendString);
                menuViewHandle.handleServiceImpl(serviceimplPackageExtendString, serviceimplMethodExtendString, serviceimplPropertyExtendString);
                menuViewHandle.handleWrapper(wrapperExtendString);
            }

            // 结束

//            List<TableEntity> tableEntities = parseXmlUtil.getTableEntities();
            createPojo.createPoJo(tableEntities, freeMarkUtil);

            Map<String, Object> data = new HashMap<>();
            data.put("packageExtend", voPackageExtendString);
            data.put("propertyExtend", voPropertyExtendString);
            CreateFactory.createByTemplate(packageMaps, voJavaPath, tableEntities, freeMarkUtil, "voTemplate.ftl", new VoParseHandle(data));
            data.put("methodExtend", mapperMethodExtendString);
            data.put("packageExtend", mapperPackageExtendString);
            CreateFactory.createByTemplate(packageMaps, mapperJavaPath, tableEntities, freeMarkUtil, "mapper.ftl", new MapperParseHandle(data));
            data.put("methodExtend", serviceMethodExtendString);
            data.put("packageExtend", servicePackageExtendString);
            CreateFactory.createByTemplate(packageMaps, servicePath, tableEntities, freeMarkUtil, "Service.java", new ServiceParseHandle(data));
            data.put("methodExtend", serviceimplMethodExtendString);
            data.put("packageExtend", serviceimplPackageExtendString);
            data.put("propertyExtend", serviceimplPropertyExtendString);
            CreateFactory.createByTemplate(packageMaps, serviceimplPath, tableEntities, freeMarkUtil, "ServiceImpl.java", new ServiceimplParseHandle(data));
            data.put("sql", mapperXmlExtendString);
            CreateFactory.createByTemplate(packageMaps, mapperJavaPath, tableEntities, freeMarkUtil, "mapperXml.ftl", new MapperXmlParseHandle(data));
            data.put("methodExtend", controllerMethodExtendString);
            data.put("packageExtend", controllerPackageExtendString);
            data.put("propertyExtend", controllerPropertyExtendString);
            CreateFactory.createByTemplate(packageMaps, controllerPath, tableEntities, freeMarkUtil, "controller.ftl", new ControllerParseHandle(data));
            data.put("like", wrapperExtendString);
            CreateFactory.createByTemplate(packageMaps, wrapperPath, tableEntities, freeMarkUtil, "Wrapper.java", new WrapperParseHandle(data));
        } catch (Exception e) {
            e.printStackTrace();
            getLog().error(e.getMessage());
        }

    }

    public String getJavaPath(String absolutePaht, String module, String packageName) {
        return new File(absolutePaht + "/" + module + "\\src\\main\\java\\" + packageName.replace(".", "/")).getAbsolutePath();
    }

    private void initWraperPackage(Map<String, String> map) {
        String voPackage = map.get("voPackage");
        String[] split = voPackage.split("\\.");
        split[(split.length - 1)] = "wrapperImpl";
        String join = StringUtils.join(split, '.');
        map.put("wrapperPackage", join);
    }

    private List<TableEntity> getTableEntitys() {
        Object o = null;
        ObjectInputStream objectInputStream = null;
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            objectInputStream = new ObjectInputStream(fileInputStream);
            o = objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (objectInputStream != null) {
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return (List<TableEntity>) (((Map<String, Object>) o).get("tables"));
    }

    private Map<String, Object> getDataz() {
        Object o = null;
        ObjectInputStream objectInputStream = null;
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            objectInputStream = new ObjectInputStream(fileInputStream);
            o = objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (objectInputStream != null) {
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return (Map<String, Object>) o;
    }

    private void initTableNameWithPrefix(List<TableEntity> tableEntities, String prefix) {
        for (TableEntity tableEntity : tableEntities) {
//            tableEntity.setTableNameWithPrefix(prefix + "_" + tableEntity.getRealTableName());
        }
    }

    private Map<String, String> initResultMapMeta(List<TableEntity> tableEntities) {
        Map<String, String> returnMap = new HashMap<>();
        for (int i = 0; i < tableEntities.size(); i++) {
            TableEntity tableEntity = tableEntities.get(i);
            String tableRealName = tableEntities.get(i).getRealTableName();
            StringBuilder builder = new StringBuilder();

            String format = String.format("<id column=\"%s_code\" property=\"code\" />\n" +
                            "<result column=\"%s_id\" property=\"id\"/>\n" +
                            "<result column=\"%s_code\" property=\"code\"/>\n" +
                            "<result column=\"%s_insert_date\" property=\"insertDate\"/>\n" +
                            "<result column=\"%s_update_date\" property=\"updateDate\"/>\n" +
                            "<result column=\"%s_valid\" property=\"valid\"/>\n" +
                            "<result column=\"%s_version\" property=\"version\"/>", tableRealName,
                    tableRealName, tableRealName, tableRealName, tableRealName, tableRealName, tableRealName
            );
            builder.append(format);
            builder.append('\n');
            for (RowEntity row : tableEntity.getRows()) {
                String column = tableRealName + "_" + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, row.getName());
                String format1 = String.format("<result column=\"%s\" property=\"%s\"/>", column, row.getName());
                builder.append(format1);
                builder.append('\n');
            }
            returnMap.put(tableEntities.get(i).getRealTableName(), builder.toString());
        }
        return returnMap;
    }

    private void handleRelative() {
        Map<String, Object> dataz = getDataz();
        List<TableRelative> relativeList = (List<TableRelative>) dataz.get("relativeList");
        if (relativeList == null || relativeList.size() <= 0) {
            return;
        }
        for (TableRelative tableRelative : relativeList) {
            this.handleVoExtendMap(tableRelative);
            handleMapperExtendMap(tableRelative);
            handleServiceExtendMap(tableRelative);
            handleServiceimplExtendMap(tableRelative);
            handleMapperXmlExtendString(tableRelative);
        }

    }

    public String firstLow(String s) {
        StringBuilder stringBuilder = new StringBuilder(s);
        stringBuilder.setCharAt(0, s.toLowerCase().charAt(0));
        return stringBuilder.toString();
    }

    private void handleVoExtendMap(TableRelative tableRelative) {
        String table1 = tableRelative.getTable1();
        String table2 = tableRelative.getTable2();
        List<String> table1ExtendPackage = voPackageExtendString.get(table1);
        List<String> table1ExtendProperty = voPropertyExtendString.get(table1);
        if (table1ExtendPackage == null) {
            table1ExtendPackage = new ArrayList<>();
            voPackageExtendString.put(table1, table1ExtendPackage);
        }
        if (table1ExtendProperty == null) {
            table1ExtendProperty = new ArrayList<>();
            voPropertyExtendString.put(table1, table1ExtendProperty);
        }

        List<String> table2ExtendPackage = voPackageExtendString.get(table2);
        List<String> table2ExtendProperty = voPropertyExtendString.get(table2);
        if (table2ExtendPackage == null) {
            table2ExtendPackage = new ArrayList<>();
            voPackageExtendString.put(table2, table2ExtendPackage);
        }
        if (table2ExtendProperty == null) {
            table2ExtendProperty = new ArrayList<>();
            voPropertyExtendString.put(table2, table2ExtendProperty);
        }
        String table2VoClassName = HumpStringUtil.humpStringHandle(table2, "_") + "Vo";
        String table1VoClassName = HumpStringUtil.humpStringHandle(table1, "_") + "Vo";
        if (tableRelative.getRelativeType().equals("2")) {
            // 处理table1
            table1ExtendProperty.add(String.format("private List<%s> %ss;", table2VoClassName, firstLow(table2VoClassName)));
            table1ExtendPackage.add(packageMaps.get("voPackage") + "." + table2VoClassName);

            // 处理table2
            table2ExtendPackage.add(packageMaps.get("voPackage") + "." + table1VoClassName);
            table2ExtendProperty.add(String.format("private %s %s;", table1VoClassName, firstLow(table1VoClassName)));
        }
        if (tableRelative.getRelativeType().equals("3")) {
            List<String> forignPackageAdd = voPackageExtendString.get(tableRelative.getForeignTable());
            List<String> forignPropertyAdd = voPropertyExtendString.get(tableRelative.getForeignTable());
            if (forignPackageAdd == null) {
                forignPackageAdd = new ArrayList<>();
                voPackageExtendString.put(tableRelative.getForeignTable(), forignPackageAdd);
            }
            if (forignPropertyAdd == null) {
                forignPropertyAdd = new ArrayList<>();
                voPropertyExtendString.put(tableRelative.getForeignTable(), forignPropertyAdd);
            }
            // 处理table1
            String forginVoClassName = HumpStringUtil.humpStringHandle(tableRelative.getForeignTable(), "_") + "Vo";
            table1ExtendProperty.add(String.format("private List<%s> %ss;", forginVoClassName, firstLow(forginVoClassName)));
            table1ExtendPackage.add(packageMaps.get("voPackage") + "." + forginVoClassName);
            // 处理table2
            table2ExtendPackage.add(packageMaps.get("voPackage") + "." + forginVoClassName);
            table2ExtendProperty.add(String.format("private List<%s> %ss;", forginVoClassName, firstLow(forginVoClassName)));
            // 处理forign
            forignPackageAdd.add(packageMaps.get("voPackage") + "." + table1VoClassName);
            forignPropertyAdd.add(String.format("private List<%s> %ss;", table1VoClassName, firstLow(table1VoClassName)));
            forignPackageAdd.add(packageMaps.get("voPackage") + "." + table2VoClassName);
            forignPropertyAdd.add(String.format("private List<%s> %ss;", table2VoClassName, firstLow(table2VoClassName)));
        }
    }

    private void handleMapperExtendMap(TableRelative tableRelative) {
        String table1 = tableRelative.getTable1();
        String table2 = tableRelative.getTable2();
        List<String> table1MapperMethod = mapperMethodExtendString.get(table1);
        List<String> table1MapperPackage = mapperPackageExtendString.get(table1);
        if (table1MapperMethod == null) {
            table1MapperMethod = new ArrayList<>();
            mapperMethodExtendString.put(table1, table1MapperMethod);
        }
        if (table1MapperPackage == null) {
            table1MapperPackage = new ArrayList<>();
            mapperPackageExtendString.put(table1, table1MapperPackage);
        }

        List<String> table2ExtendMethod = mapperMethodExtendString.get(table2);
        List<String> table2ExtendPackage = mapperPackageExtendString.get(table2);
        if (table2ExtendMethod == null) {
            table2ExtendMethod = new ArrayList<>();
            mapperMethodExtendString.put(table2, table2ExtendMethod);
        }
        if (table2ExtendPackage == null) {
            table2ExtendPackage = new ArrayList<>();
            mapperPackageExtendString.put(table2, table2ExtendPackage);
        }
        String table1ClassVoName = HumpStringUtil.humpStringHandle(table1, "_") + "Vo";
        String table1ClassName = HumpStringUtil.humpStringHandle(table1, "_");
        String table2ClassVoName = HumpStringUtil.humpStringHandle(table2, "_") + "Vo";
        String table2ClassName = HumpStringUtil.humpStringHandle(table2, "_");
        table1MapperMethod.add(String.format("List<%s> %sAnd%s(Page page, %s %s);",
                table1ClassVoName,
                firstLow(table1ClassName),
                table2ClassName,
                table1ClassVoName,
                firstLow(table1ClassVoName)
        ));
        table2ExtendMethod.add(String.format("List<%s> %sAnd%s(Page page, %s %s);",
                table2ClassVoName,
                firstLow(table2ClassName),
                table1ClassName,
                table2ClassVoName,
                firstLow(table2ClassVoName)
        ));

    }

    private void handleServiceExtendMap(TableRelative tableRelative) {
        String table1 = tableRelative.getTable1();
        String table2 = tableRelative.getTable2();
        List<String> table1ServiceMethod = serviceMethodExtendString.get(table1);
        List<String> table1ServicePackage = servicePackageExtendString.get(table1);
        if (table1ServiceMethod == null) {
            table1ServiceMethod = new ArrayList<>();
            serviceMethodExtendString.put(table1, table1ServiceMethod);
        }
        if (table1ServicePackage == null) {
            table1ServicePackage = new ArrayList<>();
            servicePackageExtendString.put(table1, table1ServicePackage);
        }

        List<String> table2ServiceMethod = serviceMethodExtendString.get(table2);
        List<String> table2ServicePackage = servicePackageExtendString.get(table2);
        if (table2ServiceMethod == null) {
            table2ServiceMethod = new ArrayList<>();
            serviceMethodExtendString.put(table2, table2ServiceMethod);
        }
        if (table2ServicePackage == null) {
            table2ServicePackage = new ArrayList<>();
            servicePackageExtendString.put(table2, table2ServicePackage);
        }
        String table1ClassVoName = HumpStringUtil.humpStringHandle(table1, "_") + "Vo";
        String table1ClassName = HumpStringUtil.humpStringHandle(table1, "_");
        String table2ClassVoName = HumpStringUtil.humpStringHandle(table2, "_") + "Vo";
        String table2ClassName = HumpStringUtil.humpStringHandle(table2, "_");
        table1ServiceMethod.add(String.format("List<%s> %sAnd%s(Page page, %s %s);",
                table1ClassVoName,
                firstLow(table1ClassName),
                table2ClassName,
                table1ClassVoName,
                firstLow(table1ClassVoName)
        ));
        table2ServiceMethod.add(String.format("List<%s> %sAnd%s(Page page, %s %s);",
                table2ClassVoName,
                firstLow(table2ClassName),
                table1ClassName,
                table2ClassVoName,
                firstLow(table2ClassVoName)
        ));

    }

    private void handleServiceimplExtendMap(TableRelative tableRelative) {
        String table1 = tableRelative.getTable1();
        String table2 = tableRelative.getTable2();
        List<String> table1Method = serviceimplMethodExtendString.get(table1);
        List<String> table1Package = serviceimplPackageExtendString.get(table1);
        if (table1Method == null) {
            table1Method = new ArrayList<>();
            serviceimplMethodExtendString.put(table1, table1Method);
        }
        if (table1Package == null) {
            table1Package = new ArrayList<>();
            serviceimplPackageExtendString.put(table1, table1Package);
        }

        List<String> table2Method = serviceimplMethodExtendString.get(table2);
        List<String> table2Package = serviceimplPackageExtendString.get(table2);
        if (table2Method == null) {
            table2Method = new ArrayList<>();
            serviceimplMethodExtendString.put(table2, table2Method);
        }
        if (table2Package == null) {
            table2Package = new ArrayList<>();
            serviceimplPackageExtendString.put(table2, table2Package);
        }
        String table1ClassVoName = HumpStringUtil.humpStringHandle(table1, "_") + "Vo";
        String table1ClassName = HumpStringUtil.humpStringHandle(table1, "_");
        String table2ClassVoName = HumpStringUtil.humpStringHandle(table2, "_") + "Vo";
        String table2ClassName = HumpStringUtil.humpStringHandle(table2, "_");
        table1Method.add(String.format("    @Override\n" +
                        "    public List<%s> %sAnd%s(Page page, %s %sVo) {\n" +
                        "        return %sMapper.%sAnd%s(page, %sVo);\n" +
                        "    }",
                table1ClassVoName,
                firstLow(table1ClassName),
                table2ClassName,
                table1ClassVoName,
                firstLow(table1ClassName),
                firstLow(table1ClassName),
                firstLow(table1ClassName),
                table2ClassName,
                firstLow(table1ClassName)
        ));
        table2Method.add(String.format("    @Override\n" +
                        "    public List<%sVo> %sAnd%s(Page page, %sVo %sVo) {\n" +
                        "        return %sMapper.%sAnd%s(page, %sVo);\n" +
                        "    }",
                table2ClassName,
                firstLow(table2ClassName),
                table1ClassName,
                table2ClassName,
                firstLow(table2ClassName),
                firstLow(table2ClassName),
                firstLow(table2ClassName),
                table1ClassName,
                firstLow(table2ClassName)
        ));

    }

    void handleMapperXmlExtendString(TableRelative tableRelative) {
        String table1 = tableRelative.getTable1();
        String table2 = tableRelative.getTable2();
        String foreign = tableRelative.getForeignTable();

        List<String> table1List = mapperXmlExtendString.get(table1);
        if (table1List == null) {
            table1List = new ArrayList<>();
            mapperXmlExtendString.put(table1, table1List);
        }
        List<String> table2List = mapperXmlExtendString.get(table2);
        if (table2List == null) {
            table2List = new ArrayList<>();
            mapperXmlExtendString.put(table2, table2List);
        }
        String table1ClassName = HumpStringUtil.humpStringHandle(table1, "_");
        String table2ClassName = HumpStringUtil.humpStringHandle(table2, "_");
        if (tableRelative.getRelativeType().equals("2")) {
            FreeMarkUtil freeMarkUtil = new FreeMarkUtil(sql1, null);
            Map<String, Object> data = new HashMap<>();
            data.put("voPackage", packageMaps.get("voPackage"));
            data.put("table1", table1);
            data.put("table2", table2);
            data.put("table1Rows", getRowsAndFormat(table1));
            data.put("table2Rows", getRowsAndFormat(table2));
            data.put("table1ClassName", table1ClassName);
            data.put("table2ClassName", table2ClassName);
            data.put("prefix", prefix);
            data.put("table1Result", resultMapMeta.get(table1));
            data.put("table2Result", resultMapMeta.get(table2));
            data.put("table1key", CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, tableRelative.getMoreProperty().get(table1)));
            data.put("table2key", CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, tableRelative.getMoreProperty().get(table2)));
            table1List.add(freeMarkUtil.parse(data));
            freeMarkUtil = new FreeMarkUtil(sql2, null);
            table2List.add(freeMarkUtil.parse(data));
        } else if (tableRelative.getRelativeType().equals("3")) {
            FreeMarkUtil freeMarkUtil = new FreeMarkUtil(sql3, null);
            Map<String, Object> data = new HashMap<>();
            data.put("voPackage", packageMaps.get("voPackage"));
            data.put("table1", table1);
            data.put("table2", table2);
            data.put("foreign", foreign);
            data.put("table1Rows", getRowsAndFormat(table1));
            data.put("table2Rows", getRowsAndFormat(table2));
            data.put("foreignRows", getRowsAndFormat(foreign));
            data.put("table1ClassName", table1ClassName);
            data.put("table2ClassName", table2ClassName);
            data.put("foreignClassName", HumpStringUtil.humpStringHandle(foreign, "_"));
            data.put("prefix", prefix);
            data.put("table1Result", resultMapMeta.get(table1));
            data.put("table2Result", resultMapMeta.get(table2));
            data.put("foreignResult", resultMapMeta.get(foreign));
            data.put("table1key", CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, tableRelative.getMoreProperty().get(table1)));
            data.put("table2key", CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, tableRelative.getMoreProperty().get(table2)));
            data.put("foreignTable1Key", CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, tableRelative.getForeign().get(table1)));
            data.put("foreignTable2Key", CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, tableRelative.getForeign().get(table2)));
            table1List.add(freeMarkUtil.parse(data));
            freeMarkUtil = new FreeMarkUtil(sql4, null);
            table2List.add(freeMarkUtil.parse(data));
        }
    }
    List<String> getRowsAndFormat(String tableName) {
        Optional<TableEntity> first = tableEntities.stream().filter(e -> e.getRealTableName().equals(tableName)).findFirst();
        if (first.isPresent()) {
            List<String> collect = first.get().getRows().stream().map(RowEntity::getName).collect(Collectors.toList());
            List<String> returnvalue =new ArrayList<>();
            for (String s : collect) {
                returnvalue.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, s));
            }
            return returnvalue;
        }
        return null;
    }

    String sql4 = "    <resultMap id=\"${table2ClassName}${table1ClassName}ResultMap\" type=\"${voPackage}.${table2ClassName}Vo\">\n" +
            "    \t${table2Result}\n" +
            "        <collection property=\"${foreignClassName?uncap_first}Vos\" ofType=\"${voPackage}.${foreignClassName}Vo\">\n" +
            "            ${foreignResult}\n" +
            "            <collection property=\"${table1ClassName?uncap_first}Vos\" ofType=\"${voPackage}.${table1ClassName}Vo\">\n" +
            "                ${table1Result}\n" +
            "            </collection>\n" +
            "        </collection>\n" +
            "    </resultMap>\n" +
            "\n" +
            "    <select id=\"${table2ClassName?uncap_first}And${table1ClassName}\" resultMap=\"${table2ClassName}${table1ClassName}ResultMap\">\n" +
            "    select\n" +
            "    ${prefix}_${table1}.id ${table1}_id,\n" +
            "    ${prefix}_${table1}.code ${table1}_code,\n" +
            "    ${prefix}_${table1}.insert_date ${table1}_insert_date,\n" +
            "    ${prefix}_${table1}.update_date ${table1}_update_date,\n" +
            "    ${prefix}_${table1}.valid ${table1}_valid,\n" +
            "    ${prefix}_${table1}.version ${table1}_version,\n" +
            "    <#list table1Rows as row>\n" +
            "\t${prefix}_${table1}.${row} ${table1}_${row},\n" +
            "\t</#list>\n" +
            "    <#list foreignRows as row>\n" +
            "\t${prefix}_${foreign}.${row} ${foreign}_${row},\n" +
            "\t</#list>\n" +
            "    ${prefix}_${foreign}.id ${foreign}_id,\n" +
            "    ${prefix}_${foreign}.code ${foreign}_code,\n" +
            "    ${prefix}_${foreign}.insert_date ${foreign}_insert_date,\n" +
            "    ${prefix}_${foreign}.update_date ${foreign}_update_date,\n" +
            "    ${prefix}_${foreign}.valid ${foreign}_valid,\n" +
            "    ${prefix}_${foreign}.version ${foreign}_version,\n" +
            "    <#list table2Rows as row>\n" +
            "\t${prefix}_${table2}.${row} ${table2}_${row},\n" +
            "\t</#list>\n" +
            "    ${prefix}_${table2}.id ${table2}_id,\n" +
            "    ${prefix}_${table2}.code ${table2}_code,\n" +
            "    ${prefix}_${table2}.insert_date ${table2}_insert_date,\n" +
            "    ${prefix}_${table2}.update_date ${table2}_update_date,\n" +
            "    ${prefix}_${table2}.valid ${table2}_valid,\n" +
            "    ${prefix}_${table2}.version ${table2}_version\n" +
            "    from ${prefix}_${table2}\n" +
            "    left join ${prefix}_${foreign}\n" +
            "    on  ${prefix}_${foreign}.${foreignTable2Key} = ${prefix}_${table2}.${table2key}\n" +
            "    left join ${prefix}_${table1}\n" +
            "    on ${prefix}_${foreign}.${foreignTable1Key} = ${prefix}_${table1}.${table1key}\n" +
            "    <where>\n" +
            "        ${prefix}_${table1}.valid = 1 and ${prefix}_${foreign}.valid = 1 and ${prefix}_${table2}.valid = 1\n" +
            "    </where>\n" +
            "    </select>\n";

    String sql3 = "    <resultMap id=\"${table1ClassName}${table2ClassName}ResultMap\" type=\"${voPackage}.${table1ClassName}Vo\">\n" +
            "    \t${table1Result}\n" +
            "        <collection property=\"${foreignClassName?uncap_first}Vos\" ofType=\"${voPackage}.${foreignClassName}Vo\">\n" +
            "            ${foreignResult}\n" +
            "            <collection property=\"${table2ClassName?uncap_first}Vos\" ofType=\"${voPackage}.${table2ClassName}Vo\">\n" +
            "                ${table2Result}\n" +
            "            </collection>\n" +
            "        </collection>\n" +
            "    </resultMap>\n" +
            "\n" +
            "    <select id=\"${table1ClassName?uncap_first}And${table2ClassName}\" resultMap=\"${table1ClassName}${table2ClassName}ResultMap\">\n" +
            "    select\n" +
            "    ${prefix}_${table1}.id ${table1}_id,\n" +
            "    ${prefix}_${table1}.code ${table1}_code,\n" +
            "    ${prefix}_${table1}.insert_date ${table1}_insert_date,\n" +
            "    ${prefix}_${table1}.update_date ${table1}_update_date,\n" +
            "    ${prefix}_${table1}.valid ${table1}_valid,\n" +
            "    ${prefix}_${table1}.version ${table1}_version,\n" +
            "    <#list table1Rows as row>\n" +
            "\t${prefix}_${table1}.${row} ${table1}_${row},\n" +
            "\t</#list>\n" +
            "    <#list foreignRows as row>\n" +
            "\t${prefix}_${foreign}.${row} ${foreign}_${row},\n" +
            "\t</#list>\n" +
            "    ${prefix}_${foreign}.id ${foreign}_id,\n" +
            "    ${prefix}_${foreign}.code ${foreign}_code,\n" +
            "    ${prefix}_${foreign}.insert_date ${foreign}_insert_date,\n" +
            "    ${prefix}_${foreign}.update_date ${foreign}_update_date,\n" +
            "    ${prefix}_${foreign}.valid ${foreign}_valid,\n" +
            "    ${prefix}_${foreign}.version ${foreign}_version,\n" +
            "    <#list table2Rows as row>\n" +
            "\t${prefix}_${table2}.${row} ${table2}_${row},\n" +
            "\t</#list>\n" +
            "    ${prefix}_${table2}.id ${table2}_id,\n" +
            "    ${prefix}_${table2}.code ${table2}_code,\n" +
            "    ${prefix}_${table2}.insert_date ${table2}_insert_date,\n" +
            "    ${prefix}_${table2}.update_date ${table2}_update_date,\n" +
            "    ${prefix}_${table2}.valid ${table2}_valid,\n" +
            "    ${prefix}_${table2}.version ${table2}_version\n" +
            "    from ${prefix}_${table1}\n" +
            "    left join ${prefix}_${foreign}\n" +
            "    on  ${prefix}_${foreign}.${foreignTable1Key} = ${prefix}_${table1}.${table1key}\n" +
            "    left join ${prefix}_${table2}\n" +
            "    on ${prefix}_${foreign}.${foreignTable2Key} = ${prefix}_${table2}.${table2key}\n" +
            "    <where>\n" +
            "        ${prefix}_${table1}.valid = 1 and ${prefix}_${foreign}.valid = 1 and ${prefix}_${table2}.valid = 1\n" +
            "    </where>\n" +
            "    </select>";

    String sql2 = "<resultMap id=\"${table2ClassName}${table1ClassName}ResultMap\" type=\"${voPackage}.${table2ClassName}Vo\">\n" +
            "    \t${table2Result}\n" +
            "        <association property=\"${table1ClassName?uncap_first}Vo\" javaType=\"${voPackage}.${table1ClassName}Vo\">\n" +
            "\t\t${table1Result}\n" +
            "        </association>\n" +
            "    </resultMap>\n" +
            "\n" +
            "\n" +
            "    <select id=\"${table2ClassName?uncap_first}And${table1ClassName}\" resultMap=\"${table2ClassName}${table1ClassName}ResultMap\">\n" +
            "        SELECT\n" +
            "        ${prefix}_${table1}.id ${table1}_id,\n" +
            "        ${prefix}_${table1}.code ${table1}_code,\n" +
            "        ${prefix}_${table1}.insert_date ${table1}_insert_date,\n" +
            "        ${prefix}_${table1}.update_date ${table1}_update_date,\n" +
            "        ${prefix}_${table1}.valid ${table1}_valid,\n" +
            "        ${prefix}_${table1}.version ${table1}_version,\n" +
            "        <#list table1Rows as row>\n" +
            "        ${prefix}_${table1}.${row} ${table1}_${row},\n" +
            "\t\t</#list>\n" +
            "        <#list table2Rows as row>\n" +
            "        ${prefix}_${table2}.${row} ${table2}_${row},\n" +
            "\t\t</#list>\n" +
            "        ${prefix}_${table2}.id ${table2}_id,\n" +
            "        ${prefix}_${table2}.code ${table2}_code,\n" +
            "        ${prefix}_${table2}.insert_date ${table2}_insert_date,\n" +
            "        ${prefix}_${table2}.update_date ${table2}_update_date,\n" +
            "        ${prefix}_${table2}.valid ${table2}_valid,\n" +
            "        ${prefix}_${table2}.version ${table2}_version\n" +
            "        from ${prefix}_${table2}\n" +
            "        left JOIN ${prefix}_${table1}\n" +
            "        on ${prefix}_${table1}.${table1key} = ${prefix}_${table2}.${table2key}\n" +
            "        <where>\n" +
            "            ${prefix}_${table1}.valid = 1 and ${prefix}_${table2}.valid = 1\n" +
            "        </where>\n" +
            "    </select>";

    String sql1 = "    <resultMap id=\"${table1ClassName}${table2ClassName}ResultMap\" type=\"${voPackage}.${table1ClassName}Vo\">\n" +
            "        ${table1Result}\n" +
            "        <collection property=\"${table2ClassName?uncap_first}Vos\" ofType=\"${voPackage}.${table2ClassName}Vo\">\n" +
            "            ${table2Result}\n" +
            "        </collection>\n" +
            "    </resultMap>\n" +
            "    <select id=\"${table1ClassName?uncap_first}And${table2ClassName}\" resultMap=\"${table1ClassName}${table2ClassName}ResultMap\">\n" +
            "        SELECT\n" +
            "        ${prefix}_${table1}.id ${table1}_id,\n" +
            "        ${prefix}_${table1}.code ${table1}_code,\n" +
            "        ${prefix}_${table1}.insert_date ${table1}_insert_date,\n" +
            "        ${prefix}_${table1}.update_date ${table1}_update_date,\n" +
            "        ${prefix}_${table1}.valid ${table1}_valid,\n" +
            "        ${prefix}_${table1}.version ${table1}_version,\n" +
            "        <#list table1Rows as row>\n" +
            "        ${prefix}_${table1}.${row} ${table1}_${row},\n" +
            "\t\t</#list>\n" +
            "        <#list table2Rows as row>\n" +
            "        ${prefix}_${table2}.${row} ${table2}_${row},\n" +
            "\t\t</#list>\n" +
            "        ${prefix}_${table2}.id ${table2}_id,\n" +
            "        ${prefix}_${table2}.code ${table2}_code,\n" +
            "        ${prefix}_${table2}.insert_date ${table2}_insert_date,\n" +
            "        ${prefix}_${table2}.update_date ${table2}_update_date,\n" +
            "        ${prefix}_${table2}.valid ${table2}_valid,\n" +
            "        ${prefix}_${table2}.version ${table2}_version\n" +
            "        from ${prefix}_${table1}\n" +
            "        left JOIN ${prefix}_${table2}\n" +
            "        on ${prefix}_${table1}.${table1key} = ${prefix}_${table2}.${table2key}\n" +
            "        <where>\n" +
            "            ${prefix}_${table1}.valid = 1 and ${prefix}_${table2}.valid = 1\n" +
            "        </where>\n" +
            "    </select>";

}
